////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file   CollabRCBot\MemberVariableTreeNode.h
///
/// @brief  Declares the CollabRC::Bot::AI::MemberVariableTreeNode class
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#include "exceptions.h"
#include "ComputationalTreeNode.h"
#include "ComputationalTreeNodeVisitor.h"
#include <QtCore/QHash>
#include <QtCore/QReadWriteLock>

namespace CollabRC
{
    namespace Bot
    {
        namespace AI
        {
            /**
             * @brief Implementation of a ComputationalTreeNode which allows
             * for variables to be specified via a pointer-to-member
             * instead of a pointer to a variable.
             *
             * A MemberVariableTreeNode is useful instead of a traditional
             * VariableTreeNode for situations where the object containing
             * the variable may change and thus must be tracked along with
             * the variable itself.
             * @version $Id$
             * @author Matthew P. Del Buono
             * @tparam C the class containing the member variable
             * @tparam T the type of the member variable to track
             */
            template <class C, class T>
            class MemberVariableTreeNode : public ComputationalTreeNode
            {
            private:
                const volatile C* m_object;
                const T C::* m_member;
            public:
                /**
                 * @brief Creates a new MemberVariableTreeNode for the specified object and member
                 * @param object the object from which to retrieve the variable
                 * @param member a pointer-to-member identifying the member to query during computation
                 * @warning The object must remain valid while this MemberVariableTreeNode
                 * points to the object
                 */
                MemberVariableTreeNode(const C& object, const T C::* member):
                  m_object(&object),m_member(member) { };

                /**
                 * @brief Creates a new MemberVariableTreeNode which represents the
                 * same object and member as the specified MemberVariableTreeNode
                 * @param copy the object from which to copy the reference to
                 * the object and pointer-to-member
                 */
                MemberVariableTreeNode(const MemberVariableTreeNode& copy):
                  m_object(copy.m_object),m_member(copy.m_member) { };

                /** @brief destroys this MemberVariableTreeNode and all associated resources */
                virtual ~MemberVariableTreeNode(void) { }

                /** {@inheritDoc} */
                virtual float Compute() const
                {
                    return m_object->*m_member;
                }

                /** {@inheritDoc} */
                virtual unsigned int GetBranchDepth() const
                {
                    return 1;
                }

                /** {@inheritDoc} */
                virtual const ComputationalTreeNode& GetRandomBranch(unsigned int depth) const
                {
                    depth = depth;  // Avoid "unreferenced formal parameter" warnings
                    return *this;
                }

                /** {@inheritDoc} */
                virtual ComputationalTreeNode* Clone() const
                {
                    return new MemberVariableTreeNode(*this);
                }

                /** {@inheritDoc} */
                virtual ComputationalTreeNode* Mutate(unsigned int depth) const
                {
                    depth = depth; // Avoid warnings

                    // Cannot mutate this object
                    IllegalMutationException ex;
                    throw ex;
                }

                /**
                 * @brief Sets the object from which to query the data
                 * @param object the object from which to query the member
                 * @warning the object must remain valid while this
                 * MemberVariableTreeNode points to the object
                 */
                void SetObject(const C& object)
                {
                    m_object = &object;
                }

                virtual void Accept(ComputationalTreeNodeVisitor& visitor)
                {
                    visitor.Visit(*this);
                }
            };

        }
    }
}
